package aop04;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

public class MethodCacheAdvice implements MethodInterceptor {

    private static Map<Key,Object> results=new HashMap<Key,Object>();

    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {

        Object target=invocation.getThis();
        Method method=invocation.getMethod();
        Object[] args=invocation.getArguments();


        Key key=new Key(target,method,args);


        Object result=results.get(key);

        if(result==null){
            result=invocation.proceed();
            results.put(key,result);
        }

        return result;
    }

    private class Key{
        private Object target;
        private Method method;
        private Object[] args;

        public Key(Object target, Method method, Object[] args) {
            this.target = target;
            this.method = method;
            this.args = args;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            Key key = (Key) o;
            return Objects.equals(target, key.target) &&
                    Objects.equals(method, key.method) &&
                    Arrays.equals(args, key.args);
        }

        @Override
        public int hashCode() {
            int result = Objects.hash(target, method);
            result = 31 * result + Arrays.hashCode(args);
            return result;
        }
    }
}
